﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "CmdSetupWorkPlaneByPick.h"
#include "IFace.h"
#include "IPlane.h"
#include "IUiView.h"
#include "IDocument.h"
#include "IWorkPlane.h"
#include "IModelView.h"
#include "IHighlights.h"
#include "IUiDocument.h"
#include "IPickFilter.h"
#include "IPickTarget.h"
#include "IRegenerator.h"
#include "IGraphicsNode.h"
#include "IGraphicsPlane.h"
#include "IElementStatus.h"
#include "IPreHighlights.h"
#include "ITrimmedSurface.h"
#include "IReferencePlane.h"
#include "GcmpCommandState.h"
#include "IUserTransaction.h"
#include "InteractivePicker.h"
#include "IGraphicsBRepFace.h"
#include "UiDocumentViewUtils.h"
#include "IUiDocumentViewManager.h"
#include "IGraphicsNodeReference.h"

#include "CommandIds.h"
#include "CommandRegister.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace Sample;

class PlanePickFilter : public IPickFilter
{

public:
    virtual bool AllowElement(const ElementId& elementId) const override
    {
        return true;
    }

    /// 只有平面可以被拾取
    virtual bool AllowGraphicsNode(const IGraphicsNodeReference& graphicsNodeReference) const override
    {
        const IGraphicsNode* pGNode = graphicsNodeReference.GetUntransformedIntersectGraphicsNode();
        if (const IGraphicsBRepFace* pGRepFace = quick_cast<IGraphicsBRepFace>(pGNode))
        {
            const IFace* pFace = pGRepFace->GetGmFace();
            if (const ITrimmedSurface* pTrimmedSurface = pFace->GetTrimmedSurface())
            {
                return pTrimmedSurface->IsPlanar();
            }
        }
        else if (const IGraphicsPlane* pGPlane = quick_cast<IGraphicsPlane>(pGNode))
        {
            return true;
        }
        return false;
    }

    /// 只有面可以被拾取
    virtual bool SetPickTargetOption(IPickTarget* pickTarget) override
    {
        pickTarget->DisableAll();
        pickTarget->EnableFace();
        return true;
    }

};

CmdSetupWorkPlaneByPick::CmdSetupWorkPlaneByPick(void)
    : CommandBase(ID_CMD_SETUP_WORK_PLANE_BY_PICK)
{
}

CmdSetupWorkPlaneByPick::~CmdSetupWorkPlaneByPick()
{
}

bool CmdSetupWorkPlaneByPick::IsEnabled() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

bool CmdSetupWorkPlaneByPick::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

OwnerPtr<IAction> CmdSetupWorkPlaneByPick::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    OwnerPtr<IPickFilter> opPickFilter = NEW_AS_OWNER_PTR(PlanePickFilter);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPickFilter, L"opPickFilter为空", L"GDMP", L"2023-11-11");
    Vector3d mousePnt;
    GraphicsNodeReferenceOwnerPtrVector gNodes;
    InteractivePicker::PickerResult pickResult = InteractivePicker::Select(false, false, TransferOwnership(opPickFilter), L"请拾取工作面平面", L"", mousePnt, gNodes);

    if (pickResult.FinishStatus == InteractivePicker::PickerFinishStatus::Successful)
    {
        OwnerPtr<IGraphicsNodeReference>& opGraphicsNodeReference = gNodes.front();
        const IGraphicsNode* pGNode = opGraphicsNodeReference->GetUntransformedIntersectGraphicsNode();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGNode, L"pGNode为空", L"GDMP", L"2023-11-11");

        // OwnerPtr的IPlane放在这里，避免pPlane指针被释放
        OwnerPtr<IPlane> opPlane;
        const IPlane* pPlane = nullptr;

        if (const IGraphicsBRepFace* pGRepFace = quick_cast<IGraphicsBRepFace>(pGNode))
        {
            const IFace* pFace = pGRepFace->GetGmFace();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFace, L"pFace为空", L"GDMP", L"2023-11-11");
            const ITrimmedSurface* pTrimmedSurface = pFace->GetTrimmedSurface();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pTrimmedSurface, L"pTrimmedSurface为空", L"GDMP", L"2023-11-11");

            if (pTrimmedSurface->GeneratePlane(opPlane))
            {
                pPlane = opPlane.get();
            }
        }
        else if (const IGraphicsPlane* pGPlane = quick_cast<IGraphicsPlane>(pGNode))
        {
            pPlane = pGPlane->GetGmIPlane();
        }

        if (pPlane == nullptr)
        {
            return nullptr;
        }

        IDocument* pDocument = UiDocumentViewUtils::GetCurrentDocument();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDocument, L"pDocument为空", L"GDMP", L"2023-11-11");
        IModelView* pModelView = UiDocumentViewUtils::GetCurrentModelView();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空", L"GDMP", L"2023-11-11");

        gcmp::OwnerPtr<IUserTransaction> opUserTransaction = IUserTransaction::Create(pDocument, GBMP_TR(L"为设置工作平面添加参照平面"));
        {
            // 由拾取到的面创建的参照平面，并设为不可见
            IReferencePlane* pCreatedRefPlane = IReferencePlane::Create(pDocument, pPlane);
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCreatedRefPlane, L"pCreatedRefPlane为空", L"GDMP", L"2023-11-20");
            IElementStatus* pStatus = pCreatedRefPlane->GetStatus();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集", L"GDMP", L"2023-11-20");
            pStatus->SetIsVisible(false);

            // 关联更新生成IGraphicsPlane
            IRegenerator* pRegenerator = pDocument->GetRegenerator();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pRegenerator, L"pRegenerator为空", L"GDMP", L"2023-11-20");
            pRegenerator->RegenerateElement(pCreatedRefPlane->GetElementId());//必须调用，用来创建IGraphicsPlane

            // 获得工作平面，并设置工作平面的参考面为新创建的IGraphicsPlane
            IWorkPlane* pWorkPlane = quick_cast<IWorkPlane>(pDocument->GetElement(pModelView->GetWorkPlaneId()));
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pWorkPlane, L"pWorkPlane为空", L"GDMP", L"2023-11-20");
            pWorkPlane->SetReferencedPlaneId(pCreatedRefPlane->GetElementId());
        }
        opUserTransaction->Commit();
        IPreHighlights::Get()->Clear();
        IHighlights::Get()->Clear();
    }
    return nullptr;
}

bool CmdSetupWorkPlaneByPick::ShouldPopExistingActionsBeforeExecution() const
{
    return false;
}

REGISTER_COMMAND(CmdSetupWorkPlaneByPick)

